package tools;

import lombok.Data;
import lombok.EqualsAndHashCode;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author wuwen
 * @since 2023/12/15
 */
public class AutoGeneratorOfMybatisUpdateModel {
    public static void main(String[] args) {
        String result = Generator.execute(Test.class, EnumNameType.SNAKE_CASE, true);
        System.out.println(result);
    }

    /**
     * xml代码的生成器
     * Example:
     * <sql id="updateModel">
     *     <if test="serviceTime != null">
     *         ServiceTime = #{serviceTime},
     *     </if>
     *     ......(此处省略)
     *     <if test="suitCorpName != null">
     *         SuitCorpName = #{suitCorpName}
     *     </if>
     * </sql>
     * 可配套以下代码使用
     * UPDATE ${tableName} SET
     *     <include refid="updateModel"/>
     * WHERE ServiceId = #{serviceId}
     * AND HandlerName = #{handlerName}
     * AND IsDelete = 0
     */
    static class Generator {
        /**
         * 执行
         *
         * @param process 要处理的类
         * @return XML代码
         */
        public static String execute(Class<?> process, EnumNameType type) {
            return Generator.execute(process, type, false);
        }

        /**
         * 执行
         *
         * @param process     要处理的类
         * @param callSuper 是否获取父类的属性，默认为false
         * @return 生成的XML代码，直接控制台复制即可
         */
        public static String execute(Class<?> process, EnumNameType type, Boolean callSuper) {
            List<Field> allFields = new ArrayList<>(List.of(process.getDeclaredFields()));
            if (callSuper) {
                List<Field> superFields = getSuperFields(process);
                while (superFields != null) {
                    allFields.addAll(superFields);
                    process = process.getSuperclass();
                    superFields = getSuperFields(process);
                }
            }
            StringBuilder sql = new StringBuilder();
            sql.append("<sql id=\"updateModel\">\n");
            int size = allFields.size();
            for (int i = 0; i < size; i++) {
                String name = allFields.get(i).getName();
                sql.append("    <if test=\"").append(name).append(" != null\">\n");
                sql.append("        ").append(EnumNameType.switchoverNameCase(name, type)).append(" = #{").append(name).append("}").append(i == size - 1 ? "" : ",").append("\n");
                sql.append("    </if>\n");
            }
            sql.append("</sql>\n");
            return sql.toString();
        }

        /**
         * 获取父类属性
         *
         * @param current 当前类
         * @return 父类属性
         */
        private static List<Field> getSuperFields(Class<?> current) {
            Class<?> superclass = current.getSuperclass();
            if (!superclass.equals(Object.class)) {
                return new ArrayList<>(List.of(superclass.getDeclaredFields()));
            }
            return null;
        }
    }

    enum EnumNameType {

        CAMEL_CASE(0, "公司风格"),

        SNAKE_CASE(3, "正常风格");

        EnumNameType(Integer code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        private final Integer code;
        private final String desc;

        public Integer code() {
            return code;
        }

        public String desc() {
            return desc;
        }

        /**
         * Java实体字段命名与数据库命名转换
         */
        private static String switchoverNameCase(String handle, EnumNameType type) {
            return switch (type) {
                case SNAKE_CASE -> {
                    StringBuilder name = new StringBuilder();
                    for (int i = 0; i < handle.length(); i++) {
                        char current = handle.charAt(i);
                        if (Character.isUpperCase(current)) {
                            name.append("_").append((char) (current + 32));
                        } else {
                            name.append(current);
                        }
                    }
                    yield name.toString();
                }
                case CAMEL_CASE -> {
                    char head = handle.charAt(0);
                    if (head >= 'A' && head <= 'Z') {
                        head = (char) (head + 32);
                    } else if (head >= 'a' && head <= 'z') {
                        head = (char) (head - 32);
                    }
                    yield head + handle.substring(1);
                }
            };
        }
    }
}

/**
 * 以下是可供测试的类
 */

@Data
@EqualsAndHashCode(callSuper = true)
class Test extends BasePersistentObject {
    private String sex;
}

@Data
@EqualsAndHashCode(callSuper = true)
class BasePersistentObject extends UltraSuperProMaxBasePersistentObject {
    private String name;
    private Integer age;
    private Long money;
}

@Data
class UltraSuperProMaxBasePersistentObject {
    private Boolean isGay;
}